#include "stdafx.h"
#include "Unicode.h"
#include <fstream>
#include <exception>
#include <io.h>
#include "resource.h"

using namespace ATL;
using namespace std;

//bool g_isSharpDevelopSolution = false;
_tstring g_pathToSharpDevelop;
_tstring g_modulePath;
IWshShellPtr g_shell;

#import "progid:SharpDevelop.SlnIconHandler" no_namespace

void registerLauncher()
{
	try
	{
		_bstr_t path = (_tstring(_T("\"")) + g_modulePath + _tstring(_T("\" \"%1\""))).c_str();
		_bstr_t key = _T("HKCR\\SharpDevelop.Launcher\\Shell\\Open\\Command\\");
		_variant_t val = path;
		g_shell->RegWrite(key, &val);
	}
	catch (_com_error err)
	{
		dbgPrint(_T("Error(0x%X): Could not register SharpLauncher. %s")
			, err.Error()
			, _tstring(err.ErrorMessage()).c_str()
			);
		throw;
	}
}

void unregisterLauncher()
{
	try
	{
		g_shell->RegDelete(_T("HKCR\\SharpDevelop.Launcher\\Shell\\Open\\Command\\"));
		g_shell->RegDelete(_T("HKCR\\SharpDevelop.Launcher\\Shell\\Open\\"));
		g_shell->RegDelete(_T("HKCR\\SharpDevelop.Launcher\\Shell\\"));
		g_shell->RegDelete(_T("HKCR\\SharpDevelop.Launcher\\"));
	}
	catch (_com_error err)
	{
		dbgPrint(_T("Error(0x%X): Could not unregister SharpLauncher. %s")
			, err.Error()
			, _tstring(err.ErrorMessage()).c_str()
			);
	}
}



void determineModulePath()
{
	TCHAR buff[2048];
	GetModuleFileName(NULL, buff, sizeof(buff));
	g_modulePath = buff;
}

struct Options
{
	Options()
		: Install(false)
		, Uninstall(false)
		, SilentMode(false)
	{

	}
	bool Install;
	bool Uninstall;
	bool SilentMode;
	_tstring SlnFileName;
};

void parseCmdLine(_tstring cmdLine, Options &options)
{
	_tstringstream ss;
	transform(cmdLine.begin(), cmdLine.end(), cmdLine.begin(), ::tolower);
	
	ss << cmdLine;
	_tstring token;

	while(ss)
	{
		ss>>token;
		if(token == _T("/u") || token == _T("/uninstall"))
			options.Uninstall = true;
		else if(token == _T("/i") || token == _T("/install"))
			options.Install = true;
		else if(token == _T("/s") || token == _T("/silent"))
			options.SilentMode = true;
		else
			options.SlnFileName = token;
	}
	
	//Install if started without any recognized arguments
	if(options.SlnFileName == _T("") && !options.Uninstall)
		options.Install = true;

	if(options.Install && options.Uninstall)
	{
		if(!options.SilentMode)
		{
			MessageBox(NULL, _T("ERROR: Cannot both install and uninstall at the same time.")
						, _T("SharpLauncher")
						, NULL);
		}
		throw _texception(_T("ERROR: Cannot both install and uninstall at the same time."));
	}
}

typedef HRESULT (__stdcall *pfnDllRegisterServer)();
typedef HRESULT (__stdcall *pfnDllUnregisterServer)();

void regServer(_tstring dllPath)
{
	if(_taccess(dllPath.c_str(), 0) == ENOENT)//Check if file exists
		throw _texception(_T("DLL (Server) not found"));

	HMODULE hModule = LoadLibrary(dllPath.c_str());

	pfnDllRegisterServer dllRegSvr = (pfnDllRegisterServer)GetProcAddress(hModule, "DllRegisterServer");

	if(dllRegSvr == NULL)
		throw _texception(_T("The specified DLL is not a valid COM server"));

	_throw_on_error(dllRegSvr());
}

void unregServer(_tstring dllPath)
{
	if(_taccess(dllPath.c_str(), 0) == ENOENT)//Check if file exists
		throw _texception(_T("DLL (Server) not found"));

	HMODULE hModule = LoadLibrary(dllPath.c_str());

	pfnDllUnregisterServer dllUnregSvr = (pfnDllUnregisterServer)GetProcAddress(hModule, "DllUnregisterServer");

	if(dllUnregSvr == NULL)
		throw _texception(_T("The specified DLL is not a valid COM server"));

	_throw_on_error(dllUnregSvr());
}

int WINAPI _tWinMain(__in HINSTANCE hInstance,
						__in_opt HINSTANCE hPrevInstance,
						__in_opt LPTSTR lpCmdLine,
						__in int nShowCmd )
{
	int retVal = EXIT_SUCCESS;
	CoInitialize(NULL);
	{
		try
		{
			g_shell.CreateInstance(__uuidof(WshShell));

			determineModulePath();

			Options options;
			parseCmdLine(lpCmdLine, options);

			if(options.Install)
			{
				registerLauncher();
				regServer(_T("SlnIconHandler.dll"));
			}
			else if(options.Uninstall)
			{
				unregisterLauncher();
				unregServer(_T("SlnIconHandler.dll"));
			}
			else if(options.SlnFileName != _T(""))
			{
				USES_CONVERSION;
				ISharpLauncherPtr launcher(_T("SharpDevelop.SlnIconHandler"));
/*				IPersistFilePtr ptr;
				launcher.QueryInterface(__uuidof(IPersistFile), &ptr);
				
				ptr->Load(T2W((LPTSTR)options.SlnFileName.c_str()), 0)*/;

				launcher->Launch(options.SlnFileName.c_str());
			}
			else
			{
				//do nothing
			}
		}
		catch (_com_error err)
		{
			dbgPrint(_T("Error(0x%X): %s")
							, err.Error()
							, _tstring(err.ErrorMessage()).c_str()
							);
			retVal = EXIT_FAILURE;
		}
		catch (_texception ex)
		{
			dbgPrint(_T("Error: %s")
						, ex.what()
						);
			retVal = EXIT_FAILURE;
		}
		g_shell = NULL;
	}
	CoUninitialize();

	return retVal;
}